#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "wffs.h"
#include "kernel.h"
#include "wffs_super.h"
#include "wffs_inode.h"
#include "sim_vfs.h"
#include "nand.h"
#include "wffs_debug.h"

static struct super_operations wffs_super_operations =
{
	.read_inode =   wffs_read_inode,
};

/*for vfs super block*/
static int wffs_sb_set(struct super_block *sb, void *data)
	{
	sb->s_fs_info = data;
	((struct wffs_sb_info *)data)->vfs_sb = sb;

	return(0);
	}

static int wffs_read_superblock(struct wffs_sb_info *sbi, uint64_t ofs)
	{
#if 0
	int ret = 0;
	uint32_t crc;
	uint64_t len, retlen;
	struct wffs_static_raw_super_block wsb;
#endif

	/* 
	 *should consier that nand can't write byte
	 *so, maybe every raw superblock obtain one page 
	 *so, maybe every block group descriptor obtin one page 
	 */
	return (0);
	}

static int wffs_load_superblock(struct wffs_sb_info *sbi)
	{
	int ret;
	ret = wffs_read_superblock(sbi, WFFS_SPACE_RESERVED_IN_HEAD);
	if (ret)
		return(ret);

	return(0);
	}

static int wffs_fill_super(struct super_block *sb)
	{

	struct wffs_sb_info *sbi = NULL;
	int ret;

	sbi = sb->s_fs_info;
	sbi->free_space_cache.rbh_root = NULL;
	ret = wffs_load_superblock(sbi);
	if (ret)
		{
		wffs_err("can't find superblock\n");
		goto err;
		}

	dbg_super("load sb success\n");
	return(0);

	err:
	return(ret);
	}

static struct super_block *wffs_get_sb(struct file_system_type *fs_type,
									   int flags, const char *dev_name,
									   void *data)
	{
	struct super_block  *sb = NULL;
	struct wffs_sb_info *sbi = NULL;
	int ret;

	sbi = malloc(sizeof(struct wffs_sb_info));
	if (!sbi)
		{
		wffs_err("can't alloc sb info\n");
		return(NULL);
		}

	memset(sbi, 0, sizeof(struct wffs_sb_info));
	sbi->mtd = flash_get_descriptor();
	if (!sbi->mtd)
		{
		wffs_err("can't get flash device\n");
		goto err;
		}

	sb = sget(fs_type, wffs_sb_set, sbi);
	if (!sb)
		{
		wffs_err("can't get sb\n");
		goto err;
		}

	sb->s_op = &wffs_super_operations;

	ret = wffs_fill_super(sb);
	if (ret)
		{
		wffs_err("can't fill super\n");
		goto err;
		}

	return(sb);

	err:
	if (sbi)
		{
		free(sbi);
		}
	return(NULL);
	}

static void wffs_kill_sb(struct super_block *sb)
	{
	return;
	}

static struct file_system_type wffs_fs_type =
{
	.name    = "wffs",
	.get_sb  = wffs_get_sb,
	.kill_sb = wffs_kill_sb,
};

int init_wffs(void)
	{
	return(register_filesystem(&wffs_fs_type));
	}

